﻿namespace Sidvall.Caching
{
	public class MemoryCache : Sidvall.Caching.ICache, System.IDisposable
	{
		#region Public Members

		#region Add

		public bool Add(CacheItem item, CacheItemPolicy policy)
		{
            if (string.IsNullOrWhiteSpace(item?.Key))
                return false;
            return this.Cache.Add(GetRuntimeCacheItem(item), GetRuntimeCacheItemPolicy(policy));
		}

		#endregion
		#region AddOrGetExisting

		public CacheItem AddOrGetExisting(CacheItem item, CacheItemPolicy policy)
		{
			return GetCacheItem(this.Cache.AddOrGetExisting(GetRuntimeCacheItem(item), GetRuntimeCacheItemPolicy(policy)));
		}

		#endregion
		#region AddOrUpdate

		public void AddOrUpdate(CacheItem item, CacheItemPolicy policy)
		{
			this.Cache.Set(GetRuntimeCacheItem(item), GetRuntimeCacheItemPolicy(policy));
		}

		#endregion
		#region Contains

		public bool Contains(string key, string regionName)
		{
			return this.Cache.Contains(key);
		}

		#endregion
		#region GetCacheItem

		public CacheItem GetCacheItem(string key, string regionName)
		{
			return GetCacheItem(this.Cache.GetCacheItem(key));
		}

		#endregion
		#region GetCacheItemValue

		public object GetCacheItemValue(string key, string regionName)
		{
			return this.Cache.Get(key);
		}

		#endregion
		#region GetCount

		public long GetCount(string regionName)
		{
			return this.Cache.GetCount();
		}

		#endregion
		#region Remove

		public object Remove(string key, string regionName)
		{
			return this.Cache.Remove(key);
		}

		#endregion

		#region Dispose

		public void Dispose()
		{
			Dispose(true);
			System.GC.SuppressFinalize(this);
		}
		protected virtual void Dispose(bool disposing)
		{
			if (!_Disposed)
			{
				if (disposing)
				{
					if (this.Cache != null)
					{
						this.Cache.Dispose();
						this.Cache = null;
					}
				}
				_Disposed = true;
			}
		}

		#endregion
		#region ToString

		public override string ToString()
		{
			return "Cache - MemoryCache";
		}

		#endregion

		#endregion
		#region Factory Members

		#region NewMemoryCache

		public static MemoryCache NewMemoryCache(string name)
		{
			MemoryCache item;

			item = new MemoryCache();
			item.Cache = new System.Runtime.Caching.MemoryCache(name);

			return item;
		}

		#endregion

		#endregion
		#region Private Members

		private System.Runtime.Caching.MemoryCache Cache { get; set; }
		private bool _Disposed = false;

		#region GetCacheItem

		private static CacheItem GetCacheItem(System.Runtime.Caching.CacheItem item)
		{
			if (item == null)
				return null;
			return new CacheItem()
			{
				Key = item.Key,
				Value = item.Value,
			};
		}

		#endregion
		#region GetRuntimeCacheItem

		private static System.Runtime.Caching.CacheItem GetRuntimeCacheItem(CacheItem item)
		{
			if (item == null)
				return null;
			return new System.Runtime.Caching.CacheItem(item.Key, item.Value);
		}

		#endregion
		#region GetRuntimeCacheItemPolicy

		private static System.Runtime.Caching.CacheItemPolicy GetRuntimeCacheItemPolicy(CacheItemPolicy item)
		{
			if (item == null)
				return null;

			var policy = new System.Runtime.Caching.CacheItemPolicy();
			if (item.AbsoluteExpiration != null)
				policy.AbsoluteExpiration = item.AbsoluteExpiration.Value;
			if (item.SlidingExpiration != null)
				policy.SlidingExpiration = item.SlidingExpiration.Value;
            switch (item.Priority)
            {
                case CacheItemPriority.NotRemovable:
                    policy.Priority = System.Runtime.Caching.CacheItemPriority.NotRemovable;
                    break;
                default:
                    policy.Priority = System.Runtime.Caching.CacheItemPriority.Default;
                    break;
            }
            return policy;
		}

		#endregion

		#endregion
		#region Constructors

		public MemoryCache()
		{
			this.Cache = System.Runtime.Caching.MemoryCache.Default;
		}

		#endregion
	}
}
